import os
import uuid
from unittest.mock import patch, MagicMock

from library_test.base_test import BaseTest


class BaseTestCommonUtils(BaseTest):

    @classmethod
    def get_module_path(cls):
        return "ascend_deployer.module_utils.common_utils"

    @classmethod
    def setUpClass(cls) -> None:
        super().setUpClass()


class TestCommonUtils(BaseTestCommonUtils):

    def test_compare_version(self):

        from ascend_deployer.module_utils.common_utils import compare_version

        src_version = "3.9.9"
        target_version = "3.10.1"

        self.assertEqual(-1, compare_version(src_version, target_version))

        src_version = "3.9.9"
        target_version = "3.9.9"
        self.assertEqual(0, compare_version(src_version, target_version))

        src_version = "3.7.5"
        target_version = "3.10.1"
        self.assertEqual(-3, compare_version(src_version, target_version))

        src_version = "3.9.9"
        target_version = "2.7.5"
        self.assertEqual(1, compare_version(src_version, target_version))

        # compare string: "test_one" < "test_two"
        src_version = "test_one"
        target_version = "test_two"
        self.assertEqual(-1, compare_version(src_version, target_version))

        # length of src_version and target_version are not same
        src_version = "3.9"
        target_version = "3.9.9"
        self.assertEqual(-1, compare_version(src_version, target_version))

    def test_get_protocol(self):

        with patch(self.get_module_path() + ".get") as mock_func:
            mock_func.return_value = "404 Not Found"
            from ascend_deployer.module_utils.common_utils import get_protocol, HTTP, HTTPS
            self.assertEqual(HTTPS, get_protocol("module", "host"))

            mock_func.return_value = "This is wrong version number"
            self.assertEqual(HTTP, get_protocol("module", "host"))

            mock_func.return_value = "The plain HTTP request was sent to HTTPS port"
            self.assertEqual(HTTPS, get_protocol("module", "host"))

            mock_func.return_value = "Random content"
            self.assertEqual(HTTP, get_protocol("module", "host"))

    def test_clean_env(self):
        env_variables = ['http_proxy', 'https_proxy', 'HTTP_PROXY', 'HTTPS_PROXY']
        for variable in env_variables:
            os.environ.setdefault(variable, str(uuid.uuid4()))
        from ascend_deployer.module_utils.common_utils import clean_env
        clean_env()
        for variable in env_variables:
            self.assertNotIn(variable, os.environ)

    def test_is_valid_ip(self):
        from ascend_deployer.module_utils.common_utils import is_valid_ip
        self.assertTrue(is_valid_ip("192.168.1.1"))
        self.assertFalse(is_valid_ip("999.999.999.999"))

        self.assertTrue(is_valid_ip("2001:0db8:85a3:0000:0000:8a2e:0370:7334"))
        self.assertFalse(is_valid_ip("xyz:xyz:xyz:xyz:xyz:xyz:xyz:xyz"))


try:
    # Python 2
    from Queue import Queue
except ImportError:
    # Python 3
    from queue import Queue


class AnsibleModuleMocker:
    def __init__(self):
        self.params = {}
        self.exit_json = MagicMock()
        self.fail_json = MagicMock()
        self.get_bin_path = MagicMock()
        self.run_command = MagicMock()


class TestMcuMultiProcess(BaseTestCommonUtils):
    def test_multi_run_command(self):
        from ascend_deployer.module_utils.common_utils import McuMultiProcess
        multi_process = McuMultiProcess([1], AnsibleModuleMocker())

        # Test execution test action failed
        with patch.object(multi_process._module, 'run_command', return_value=(1, "", "rc err")):
            results = multi_process.multi_run_command()
            self.assertEqual({1: {'error': 'MCU test failed: rc err',
                                  'output': '',
                                  'rc': -1,
                                  'success': False}}, results)

        # Test execution of test action successful
        with patch.object(multi_process._module, 'run_command', return_value=(0, "Version   : 24.2.1", "")):
            results = multi_process.multi_run_command()
            self.assertEqual({1: {'error': '', 'output': 'Version   : 24.2.1', 'rc': 0, 'success': True}}, results)

        # Test execution of upgrade action successful
        with patch.object(multi_process._module, 'run_command', return_value=(0, "Version   : 24.2.1", "")):
            results = multi_process.multi_run_command(tag='upgrade')
            self.assertEqual({1: {'activate_rc': 0,
                                  'error': '',
                                  'output': 'Version   : 24.2.1\nVersion   : 24.2.1',
                                  'rc': 0,
                                  'success': True,
                                  'upgrade_rc': 0}}, results)

        # Test execution upgrade action failed
        with patch.object(multi_process._module, 'run_command', return_value=(1, "", "rc error")):
            results = multi_process.multi_run_command(tag='upgrade')
            self.assertEqual({1: {'activate_rc': -1,
                                  'error': 'MCU upgrade failed: rc error',
                                  'output': '',
                                  'rc': -1,
                                  'success': False,
                                  'upgrade_rc': -1}}, results)

    def test__test_mcu(self):
        from ascend_deployer.module_utils.common_utils import McuMultiProcess
        multi_process = McuMultiProcess([1], AnsibleModuleMocker())

        # Test execution run_command ok
        with patch.object(multi_process._module, 'run_command', return_value=(0, "ok", "")):
            multi_process._test_mcu(1)
            self.assertEqual(multi_process._queue.get(), (1, {'error': '', 'output': 'ok', 'rc': 0, 'success': True}))

        # Test execution run_command failed
        with patch.object(multi_process._module, 'run_command', return_value=(1, "fail", "fail")):
            multi_process._test_mcu(1)
            self.assertEqual(multi_process._queue.get(),
                             (1, {'error': 'MCU test failed: fail', 'output': '', 'rc': -1, 'success': False}))

    def test_upgrade_mcu(self):
        from ascend_deployer.module_utils.common_utils import McuMultiProcess
        multi_process = McuMultiProcess([1], AnsibleModuleMocker())

        # Test execution run_command ok
        expect_value = (1,
                        {'activate_rc': 0,
                         'error': '',
                         'output': 'ok\nok',
                         'rc': 0,
                         'success': True,
                         'upgrade_rc': 0})
        with patch.object(multi_process._module, 'run_command', return_value=(0, "ok", "")):
            multi_process._upgrade_mcu(1)
            self.assertEqual(multi_process._queue.get(), expect_value)

        # Test execution run_command failed
        expect_value = (1,
                        {'activate_rc': -1,
                         'error': 'MCU upgrade failed: fail',
                         'output': '',
                         'rc': -1,
                         'success': False,
                         'upgrade_rc': -1})
        with patch.object(multi_process._module, 'run_command', return_value=(1, "fail", "fail")):
            multi_process._upgrade_mcu(1)
            self.assertEqual(multi_process._queue.get(), expect_value)
